package Controller;


import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.lang.reflect.Method;
import java.util.ArrayList;

import Model.AbstractModel;
import View.AbstractView;

/**
 *
 * This abstract class is to implement the controller functionality of MVC.
 * For more detailed description, please check
 * http://www.oracle.com/technetwork/articles/javase/mvc-136693.html
 *
 */
public abstract class AbstractController implements PropertyChangeListener {

	private final ArrayList<AbstractView> registeredViews;
	private final ArrayList<AbstractModel> registeredModels;

	public AbstractController() {
		registeredViews = new ArrayList<AbstractView>();
		registeredModels = new ArrayList<AbstractModel>();
	}

	public void addModel(AbstractModel model) {
		registeredModels.add(model);
		model.addPropertyChangeListener(this);
	}

	public void removeModel(AbstractModel model) {
		registeredModels.remove(model);
		model.removePropertyChangeListener(this);
	}

	public void addView(AbstractView view) {
		registeredViews.add(view);
	}

	public void removeView(AbstractView view) {
		registeredViews.remove(view);
	}

	/*
	 * Triggered when a bound property is changed in model
	 * @see java.beans.PropertyChangeListener#propertyChange(java.beans.PropertyChangeEvent)
	 */
	@Override
	public void propertyChange(PropertyChangeEvent evt) {
		/*System.out.println(this.getClass().toString() + ".propertyChange() called-- " +
				evt.getPropertyName() + ": " + evt.getOldValue().toString() +
				" -> " + evt.getNewValue().toString());*/
		for (AbstractView view: registeredViews) {
			view.modelPropertyChange(evt);
		}
	}

	protected void setModelProperty(String propertyName, Object newValue) {
		/*System.out.println(this.getClass().toString() + ".setModelProperty() called " + "-- set" + propertyName + "(" + newValue.getClass().toString() + ")");*/
		for (AbstractModel model: registeredModels) {
			try {
				Method method = model.getClass().
						getMethod("set" + propertyName, new Class[] { newValue.getClass() });
				method.invoke(model, newValue);
			} catch (Exception ex) {
				// Handle exception. Ignored though.
			}
		}
	}
}